package com.lfy.modules.safety.limit;

import cn.hutool.extra.spring.SpringUtil;
import com.lfy.modules.safety.blankMenu.BlackMenuCache;
import com.lfy.modules.safety.blankMenu.interfaces.BlackMenuActuator;
import com.lfy.modules.common.utils.RequestUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ThreadPoolExecutor;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 限流抽象类
 *
 * @author <a href="https://www.lvfeiy.top">lvfeiyang</a>
 * @date 2024/4/24 21:42
 */
@Slf4j
public abstract class BaseLimit implements BlackMenuActuator {
    private static final Pattern PATTERN = Pattern.compile("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
    private static final ThreadPoolExecutor MAIN_THREAD_POOL ;
    static {
        MAIN_THREAD_POOL = SpringUtil.getBean("mainThreadPool");
    }
    protected static boolean isValidIPv4(String ip) {
        return PATTERN.matcher(ip).matches();
    }
    protected abstract Integer getCount(String key,long time);


    public abstract void setCount(String key);


    /**
     * 黑名单规则
     * @return true: 触发黑名单规则, false: 不触发黑名单规则
     */
    @Override
    public boolean blackMenuRules(String key){
        String[] split = key.split("@");
        if(split.length>0){
            String subStr = split[0];
            if(isValidIPv4(subStr)){
                //IP
                BlackMenuCache.setBlack(subStr);
                log.info("IP:{}触发黑名单规则",subStr);
                return BlackMenuCache.isTriggerBlack(subStr);
            }else {
                //ID
                log.info("ID:{}触发黑名单规则",subStr);
            }
        }
        return false;
    }

    /**
     * 设置黑名单
     * @param key 黑名单key
     */
    @Override
    public void setBlackMenu(String key) {
        if(blackMenuRules(key)){
            BlackMenuCache.triggerBlack(key);
        }
    }

    /**
     * 判断是否达到限制
     * @param key key
     * @param time 从什么时候开始计算
     * @param count 限制次数
     * @return true:达到限制, false:未达到限制
     */
    public  boolean isLimited(String key,long time,Integer count,boolean isBlack){
        String[] split = key.split("@");
        if(RequestUtil.LOCAL_REMOTE_HOST1.equals(split[0])
                || RequestUtil.LOCAL_REMOTE_HOST2.equals(split[0])
                || RequestUtil.LOCAL_REMOTE_HOST3.equals(split[0])
                || RequestUtil.LOCAL_REMOTE_HOST4.equals(split[0])){
            return false;
        }
        boolean b = getCount(key,time) >= count;
        if(b && isBlack){
            MAIN_THREAD_POOL.execute(()->{
                setBlackMenu(key);
            });
        }
        return b;
    }
}
